package com.xqboss.apps.service.order.pay.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.xqboss.apps.domain.order.PayAccount;
import com.xqboss.apps.domain.order.PayApply;
import com.xqboss.apps.dto.order.SignPayDto;
import com.xqboss.apps.dto.order.TradeResultDto;
import com.xqboss.apps.service.order.PayAccountService;
import com.xqboss.apps.service.order.pay.PayExecutor;
import com.xqboss.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
public abstract class BaseAliPay extends PayExecutor {

    @Value("${pay.alipay.gateway}")
    String gateway;
    @Value("${pay.alipay.format}")
    String format;
    @Value("${pay.alipay.charset}")
    String charset;
    @Value("${pay.alipay.signType}")
    String signType;
    @Value("${pay.alipay.notifyUrl}")
    String notifyUrl;

    @Autowired
    protected PayAccountService payAccountService;

    @Override
    public TradeResultDto verifyCallback(HttpServletRequest request, Object p) {
        // 校验钱包密码
        try{
            Long payAccountId = (Long) p;
            PayAccount payAccount = payAccountService.getPayAccount(payAccountId);
            //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
            Map< String , String > params = new HashMap< String , String >();
            Map requestParams = request.getParameterMap();
            for(Iterator iter = requestParams.keySet().iterator(); iter.hasNext();){
                String name = (String)iter.next();
                String[] values = (String [])requestParams.get(name);
                String valueStr = "";
                for(int i = 0;i < values.length;i ++ ){
                    valueStr =  (i==values.length-1)?valueStr + values [i]:valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put (name,valueStr);
            }
            //调用SDK验证签名
            //公钥验签示例代码
            boolean  signVerified = AlipaySignature.rsaCheckV1(params, payAccount.getPublicKey(), charset,signType) ;
            //公钥证书验签示例代码
            //   boolean flag = AlipaySignature.rsaCertCheckV1(params,alipayPublicCertPath,"UTF-8","RSA2");
            if (signVerified){
                //  验签成功后
                //按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success
                //验证 app_id 是否为该商家本身。
                String appId = params.get("app_id");
                if(!appId.equals(payAccount.getAppId())){
                    throw new ServiceException("商户ID不一致！");
                }

                //商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
                String outTradeNo = params.get("out_trade_no");

                //判断 total_amount 是否确实为该订单的实际金额（即商家订单创建时的金额）。
                String totalAmount = params.get("total_amount");

                //校验通知中的 seller_id（或者 seller_email ) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商家可能有多个seller_id/seller_email）。

                TradeResultDto result = new TradeResultDto();
                result.setTradeNo(outTradeNo);
                result.setOutTradeNo(params.get("trade_no"));
                result.setTotalAmount(new BigDecimal(totalAmount));
                result.setBuyerId(params.get("buyer_id"));
                result.setBuyerAccount(params.get("buyer_logon_id"));
                result.setSellerId(params.get("seller_id"));
                result.setSellerAccount(params.get("seller_email"));
                result.setReceiptAmount(new BigDecimal(params.get("receipt_amount")));
                result.setPayAmount(new BigDecimal(params.get("buyer_pay_amount")));
                result.setPayTime(LocalDateTimeUtil.parse(params.get("gmt_payment"), "yyyy-MM-dd HH:mm:ss"));
                return result;
            } else {
                throw new ServiceException("验签失败!");
            }
        }catch (Exception e){
            log.error("支付宝回调异常", e);
            throw new ServiceException("验签失败!");
        }
    }

    @Override
    public TradeResultDto queryTrade(PayApply info) {
        try {
            PayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId());
            AlipayClient alipayClient = new DefaultAlipayClient(gateway, payAccount.getAppId(), payAccount.getPrivateKey(), format, charset, payAccount.getPublicKey(), signType);
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            AlipayTradeQueryModel bizModel = new AlipayTradeQueryModel();
            bizModel.setOutTradeNo(String.valueOf(info.getId()));
            bizModel.setTradeNo(info.getOutTradeNo());
            request.setBizModel(bizModel);
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                if("WAIT_BUYER_PAY".equals(response.getTradeStatus())){
                    // 未支付 交易创建，等待买家付款
                    throw new ServiceException("订单未支付!");
                }else if("TRADE_CLOSED".equals(response.getTradeStatus())){
                    // 支付关闭 未付款交易超时关闭，或支付完成后全额退款
                    throw new ServiceException("订单未支付!");
                }else if("TRADE_SUCCESS".equals(response.getTradeStatus())){
                    // 支付成功 交易支付成功
                    TradeResultDto result = new TradeResultDto();
                    result.setTradeNo(response.getOutTradeNo());
                    result.setOutTradeNo(response.getTradeNo());
                    result.setTotalAmount(new BigDecimal(response.getTotalAmount()));
                    result.setBuyerId(response.getBuyerUserId());
                    result.setBuyerAccount(response.getBuyerLogonId());
                    result.setReceiptAmount(new BigDecimal(response.getReceiptAmount()));
                    result.setPayAmount(new BigDecimal(response.getBuyerPayAmount()));
                    result.setPayTime(LocalDateTimeUtil.of(response.getSendPayDate()));
                    return result;
                }else if("TRADE_FINISHED".equals(response.getTradeStatus())){
                    //交易结束，不可退款
                    TradeResultDto result = new TradeResultDto();
                    result.setTradeNo(response.getOutTradeNo());
                    result.setOutTradeNo(response.getTradeNo());
                    result.setTotalAmount(new BigDecimal(response.getTotalAmount()));
                    result.setBuyerId(response.getBuyerUserId());
                    result.setBuyerAccount(response.getBuyerLogonId());
                    result.setReceiptAmount(new BigDecimal(response.getReceiptAmount()));
                    result.setPayAmount(new BigDecimal(response.getBuyerPayAmount()));
                    result.setPayTime(LocalDateTimeUtil.of(response.getSendPayDate()));
                    return result;
                }else{
                    log.error("获取支付状态异常：{} - {}", info.getId(), JSON.toJSONString(response));
                    throw new ServiceException("获取支付状态失败！");
                }
            } else {
                if("ACQ.TRADE_NOT_EXIST".equals(response.getSubCode())){
                    throw new ServiceException("未获取到支付信息!");
                }
                log.error("获取支付状态异常：{} - {}", info.getId(), JSON.toJSONString(response));
                throw new ServiceException("获取支付状态失败！");
            }
        } catch (ServiceException e){
            throw e;
        } catch (Exception e) {
            log.error("获取支付状态异常：{}", info.getId(), e);
            throw new ServiceException("获取支付状态失败！");
        }
    }

    @Override
    public boolean cancelPay(PayApply payApply) {
        try {
            PayAccount payAccount = payAccountService.getPayAccount(payApply.getPayAccountId());
            AlipayClient alipayClient = new DefaultAlipayClient(gateway, payAccount.getAppId(), payAccount.getPrivateKey(), format, charset, payAccount.getPublicKey(), signType);
            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
            AlipayTradeCloseModel bizModel = new AlipayTradeCloseModel();
            bizModel.setOutTradeNo(String.valueOf(payApply.getId()));
            request.setBizModel(bizModel);
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                return true;
            }
            log.error("关闭订单异常! {} - {}", payApply.getId(), JSON.toJSONString(response));
            return false;
        } catch (Exception e) {
            log.error("关闭订单异常! {}", payApply.getId(), e);
            return false;
        }
    }

}
